[Previous] [Next]

Common Properties

At first glance, it might seem that Visual Basic 6 supports countless properties for various objects. Fortunately, there's a set of properties many objects of different classes share. In this section, we'll examine these common properties.

The Left, Top, Width, and Height Properties

All visible objects—forms and controls—expose these properties, which affect the object's position and size. These values are always relative to the object's container—that is, the screen for a form and the parent form for a control. A control can also be contained in another control, which is said to be its container: In this case, Top and Left properties are relative to such a container control. By default, these properties are measured in twips, a unit that lets you create resolution-independent user interfaces, but you can switch to another unit, for example, pixels or inches, by setting the container's ScaleMode property. But you can't change the unit used for forms because they have no container: Left, Top, Width, and Height properties for forms are always measured in twips. For more information about the twip measurement unit, see the section "The ScaleMode Property" later in this chapter.

While you can enter numeric values for these properties right in the Properties window at design time, you often set them in a visual manner by moving and resizing the control on its parent form. Keep in mind that Visual Basic also offers many interactive commands in the Format menu that let you resize, align, and space multiple controls in one operation. You can also access and modify these properties through code to move or resize objects at run time:

' Double a form's width, and move it to the
' upper left corner of the screen.
Form1.Width = Form1.Width * 2
Form1.Left = 0 
Form1.Top = 0

Note that while all controls—even invisible ones—expose these four properties at design time in the Properties window, controls that are inherently invisible—Timer controls, for example—don't support these properties at run time, and you can't therefore read or modify them through code.

CAUTION
Controls don't necessarily have to support all four properties in a uniform manner. For example, ComboBox controls' Height property can be read but not written to, both at design time and run time. As far as I know, this is the only example of a property that appears in the Properties window but can't be modified at design time. This happens because the height of a ComboBox control depends on the control's Font attributes. Remember this exception when writing code that modifies the Height property for all the controls in a form.

The ForeColor and BackColor Properties

Most visible objects expose ForeColor and BackColor properties, which affect the color of the text and the color of the background, respectively. The colors of a few controls—scroll bars, for example—are dictated by Microsoft Windows, however, and you won't find ForeColor and BackColor entries in the Properties window. In other cases, the effect of these properties depends on other properties: for example, setting the BackColor property of a Label control has no effect if you set the BackStyle property of that Label to 0-Transparent. CommandButton controls are peculiar in that they expose a BackColor property but not a ForeColor property, and the background color is active only if you also set the Style property to 1-Graphical. (Because the default value for the Style property is 0-Standard, it might take you a while until you understand why the BackColor property doesn't affect the background color in the usual manner.)

When you're setting one of these two properties in the Properties window, you can select either a standard Windows color or a custom color using the System tab in the first case and the Palette tab in the second, as you can see in Figure 2-1. My first suggestion is always use a standard color value unless you have a very good reason to use a custom color. System colors display well on any Windows machine, are likely to conform to your customers' tastes, and contribute to making your application look well integrated in the system. My second suggestion is if you want to use custom colors, develop a consistent color scheme and use it throughout your application. I also have a third suggestion: Never mix standard and custom colors on the same form, and don't use a standard color for the ForeColor property and a custom color for the BackColor property of the same control (or vice versa), because the user might change the system palette in a way that makes the control completely unreadable.

You can choose from several ways to assign a color in code. Visual Basic provides a set of symbolic constants that correspond to all the colors that appear in the System tab in the Properties window at design time:

' Make Label1 appear in a selected state.
Label1.ForeColor = vbHighlightText
Label1.BackColor = vbHighlight

All the symbolic constants are shown in Table 2-1, but you can also browse them in the Object Browser window, after clicking the SystemColorConstants item in the leftmost list box. (If you don't see it, first select <All libraries> or VBRUN in the top ComboBox control). Note that all the values of these constants are negative.

Click to view at full size.

Figure 2-1. Two different ways to set the ForeColor and BackColor properties at design time.

Table 2-1. Visual Basic constants for system colors.

Constant Hex Value Description
vb3DDKShadow &H80000015 Darkest shadow
vb3Dface &H8000000F Dark shadow color for 3-D display elements
vb3Dhighlight &H80000014 Highlight color for 3-D display elements
vb3Dlight &H80000016 Second lightest of the 3-D colors after vb3Dhighlight
vb3Dshadow &H80000010 Color of automatic window shadows
vbActiveBorder &H8000000A Active window border color
vbActiveTitleBar &H80000002 Active window caption color
vbActiveTitleBarText &H80000009 Text color in active caption, size box, scroll bar arrow box
vbApplicationWorkspace &H8000000C Background color of multiple-document interface (MDI) applications
vbButtonFace &H8000000F Face shading on command buttons
vbButtonShadow &H80000010 Edge shading on command buttons
vbButtonText &H80000012 Text color on push buttons
vbDesktop &H80000001 Desktop color
vbGrayText &H80000011 Grayed (disabled) text
vbHighlight &H8000000D Background color of items selected in a control
vbHighlightText &H8000000E Text color of items selected in a control
vbInactiveBorder &H8000000B Inactive window border color
vbInactiveCaptionText &H80000013 Color of text in an inactive caption
vbInactiveTitleBar &H80000003 Inactive window caption color
vbInactiveTitleBarText &H80000013 Text color in inactive window caption, size box, scroll bar arrow box
vbInfoBackground &H80000018 Background color of ToolTips
vbInfoText &H80000017 Color of text in ToolTips
vbMenuBar &H80000004 Menu background color
vbMenuText &H80000007 Text color in menus
vbScrollBars &H80000000 Scroll bar gray area color
vbTitleBarText &H80000009 Text color in active caption, size box, scroll bar arrow box
vbWindowBackground &H80000005 Window background color
vbWindowFrame &H80000006 Window frame color
vbWindowText &H80000008 Text color in windows

When you're assigning a custom color, you can use one of the symbolic constants that Visual Basic defines for the most common colors (vbBlack, vbBlue, vbCyan, vbGreen, vbMagenta, vbRed, vbWhite, and vbYellow), or you can use a numeric decimal or hexadecimal constant:

' These statements are equivalent.
Text1.BackColor = vbCyan
Text1.BackColor = 16776960 
Text1.BackColor = &HFFFF00

You can also use an RGB function to build a color value composed of its red, green, and blue components. Finally, to ease the porting of existing QuickBasic applications, Visual Basic supports the QBColor function:

' These statements are equivalent to the ones above.
Text1.BackColor = RGB(0, 255, 255)    ' red, green, blue values
Text1.BackColor = QBColor(11)

The Font Property

Forms and those controls that can display strings of characters expose the Font property. At design time, you set font attributes using a common dialog box, which you can see in Figure 2-2. Dealing with fonts at run time, however, is less simple because you must account for the fact that Font is a compound object, and you must assign its properties separately. Font objects expose the Name, Size, Bold, Italic, Underline, and Strikethrough properties.

Text1.Font.Name = "Tahoma"
Text1.Font.Size = 12
Text1.Font.Bold = True
Text1.Font.Underline = True

Figure 2-2. At design time the Font dialog box lets you modify all font attributes at once and preview the result.

TIP
You can use the Set command to assign whole Font objects to controls (thus avoiding having to set individual font attributes for each control), as you can see in the following code fragment:

' Assign to Text2 the same font as used by Text1.
Set Text2.Font = Text1.Font

It should be made clear, however, that the preceding code actually assigns the same Font objects to both controls. This means that if you later change Text1's font attributes, the appearance of Text2 will also be affected. This behavior is perfectly consistent with the Font object's nature, even though the reasons for it will become clear only later in Chapter 6. You can take advantage of this approach—for example, if all the controls in your form always use the same font—but you should absolutely avoid it when the controls in question are supposed to have independent font attributes.

Visual Basic 6 still supports old-style Font properties such as FontName, FontSize, FontBold, FontItalic, FontUnderline, and FontStrikethru, but you can modify them only through code because they don't appear in the Properties window at design time. You can use the syntax that you like most because the two forms are perfectly interchangeable. In this book, however, I mostly follow the newer object-oriented syntax.

The Font.Size property (or the equivalent FontSize property) is peculiar because in general you can't be sure that Visual Basic is able to create a font of that particular size, especially if you aren't working with a TrueType font. The short code snippet below proves this.

Text1.Font.Name = "Courier"
Text1.Font.Size = 22
Print Text1.Font.Size  ' Prints 19.5

Note that no error is raised if you specify a font size that isn't actually available.

CAUTION
In general, Visual Basic doesn't raise errors when you try to assign invalid font names. In this case, the effect is somewhat unpredictable. For example, try the following code:

' Warning: you may get different results on your system.
Print Font.Name       ' Displays "Ms Sans Serif"
Font.Name = "xyz"
Print Font.Name       ' Displays "Arial" 

The Caption and Text Properties

The Caption property is a string of characters that appears inside a control (or in the title bar of a form) and that the user can't directly modify. Conversely, the Text property corresponds to the "contents" of a control and is usually editable by the end user. No intrinsic control exposes both a Caption and a Text property, so in practice a look at the Properties window can resolve your doubts as to what you're working with. Label, CommandButton, CheckBox, OptionButton, Data, and Frame controls expose the Caption property, whereas TextBox, ListBox, and ComboBox controls expose the Text property.

The Caption property is special in that it can include an ampersand (&) character to associate a hot key with the control. The Text property, when present, is always the default property for the control, which means that it can be omitted in code:

' These statements are equivalent.
Text2.Text = Text1.Text
Text2 = Text1

NOTE
Specifying or omitting the name of the default property in code is mostly a matter of personal taste. I always try to specify the name of all the properties referenced in code because doing so tends to make the code more readable. However, if you have long lines of code, specifying all the default properties can sometimes make the code less readable and can force you to horizontally scroll through the code window. This consideration has been followed in this book: Most of the time, I specify the default property, but don't be surprised if I sometimes omit it, especially in longer listings.

While we are on this topic, note that many programmers mistakenly believe that using default properties can make their code run faster. This is a leftover notion from Visual Basic 3 days, but it hasn't been true since Visual Basic 4 changed the internal implementation of controls.

In general, if a control exposes the Text property it also supports the SelText, SelStart, and SelLength properties, which return information about the portion of text that's currently selected in the control.

The Parent and Container Properties

The Parent property is a run time_only property (that is, you don't see it in the Properties window), which returns a reference to the form that hosts the control. The Container property is also a run time_only property, which returns a reference to the container of the control. These two properties are correlated, in that they return the same object—the parent form—when a control is placed directly on the form surface.

While you can't move a control from one form to another using the Parent property (which is read-only), you can move a control to another container by assigning a different value to its Container property (which is a read-write property). Because you're assigning objects and not plain values, you must use the Set keyword:

' Move Text1 into the Picture1 container. 
Set Text1.Container = Picture1
' Move it back on the form's surface.
Set Text1.Container = Form1

The Enabled and Visible Properties

By default, all controls and forms are both visible and enabled at run time. For a number of reasons, however, you might want to hide them or show them in a disabled state. For example, you might use a hidden DriveListBox control simply to enumerate all the drives in the system. In this case, you set the Visible property of the DriveListBox control to False in the Properties window at design time. More frequently, however, you change these properties at run time:

' Enable or disable the Text1 control when
' the user clicks on the Check1 CheckBox control.
Private Sub Check1_Click()
    Text1.Enabled = (Check1.Value = vbChecked)
End Sub

Disabled controls don't react to user's actions, but otherwise they're fully functional and can be manipulated through code. Invisible controls are automatically disabled, so you never need to set both these properties to False. All mouse events for disabled or invisible controls are passed to the underlying container or to the form itself.

If an object works as a container for other objects—for instance, a Form is a container for its controls and a Frame control can be a container for a group of OptionButton controls—setting its Visible or Enabled properties indirectly affects the state of its contained objects. This feature can often be exploited to reduce the amount of code you write to enable or disable a group of related controls.

TIP
Most controls change their appearance when they're disabled. Generally speaking, this is a useful practice because the user can understand at first glance which controls he or she can act on. If you have a good reason to disable a control but still display it in an active state, you can place the control inside a container (a Frame or a PictureBox, for example) and then set the container's Enabled property to False. Visual Basic will disable all contained controls, but they will continue to appear in an enabled state. This trick works better if you also set the container's BorderStyle property to 0-None.

Some programmers set the Enabled properties to False for TextBox or ComboBox controls that must work in a read-only mode. This is reminiscent of the way things worked under Visual Basic 3 and previous versions. But these controls now expose a Locked property that, if True, makes the controls completely functional, except that users can't modify their Text property. This means that users can scroll through their content but can't accidentally modify it.

The hWnd Property

The hWnd property doesn't appear in the Properties window because its value is available only at run time. Moreover, it's a read-only property, and therefore you can't assign a value to it. The hWnd property returns the 32-bit integer value that Windows uses internally to identify a control. This value is absolutely meaningless in standard Visual Basic programming and only becomes useful if you invoke Windows API routines (which I'll cover in Appendix A). Even if you're not going to use this property in your code, it's good for you to know that not all controls support it and it's important to understand why.

Visual Basic controls—both intrinsic controls and external Microsoft ActiveX controls—can be grouped in two categories: standard controls and windowless (or lightweight) controls. To grasp the difference between the two groups, let's compare the PictureBox control (a standard control) and the Image control (a windowless control). Even though they appear similar at a first glance, behind the scenes they are completely different.

When you place a standard control on the form, Visual Basic asks the operating system to create an instance of that control's class, and in return Windows passes back to Visual Basic the internal handle to that control, which the language then exposes to the programmer through the hWnd property. All subsequent operations that Visual Basic performs on that control—resizing, font setting, and so on—are actually delegated to Windows. When the application raises an event (such as resizing), Visual Basic runtime calls an internal Windows API function and passes it the handle so that Windows knows which control is to be affected.

Lightweight controls such as Image controls, on the other hand, don't correspond to any Windows object and are entirely managed by Visual Basic itself. In a sense, Visual Basic just simulates the existence of that control: It keeps track of all the lightweight controls and redraws them each time the form is refreshed. For this reason, lightweight controls don't expose an hWnd property because there aren't any Windows handles associated with them. Windows doesn't even know a control is there.

From a practical point of view, the distinction between standard and lightweight controls is that the former consume system resources and memory while the latter don't. For this reason, you should always try to replace standard controls with lightweight controls. For example, use an Image control instead of a PictureBox control unless you really need some of PictureBox's specific features. To give you an idea of what this means in practice, a form with 100 PictureBox controls loads 10 times slower than a form with 100 Image controls.

To understand whether a control is lightweight, see whether it supports the hWnd property. If it does, it surely is a standard control. A trip to the Object Browser reveals that the TextBox, CommandButton, OptionButton, CheckBox, Frame, ComboBox, and OLE controls, as well as both scroll bar controls and the ListBox control and all its variations, are standard controls. The Label, Shape, Line, Image, and Timer controls don't expose the hWnd property and should be therefore considered lightweight controls. But note that a missing hWnd property in an external ActiveX control doesn't necessarily mean that the control is windowless because the control's creator might decide not to expose the window's handle to the outside. For more information about standard and windowless controls, see the description of the ZOrder method later in this chapter.

The TabStop and TabIndex Properties

If a control is able to receive the input focus, it exposes the TabStop property. Most intrinsic controls support this property, including TextBox, OptionButton, CheckBox, CommandButton, OLE, ComboBox, both types of scroll bars, the ListBox control, and all its variations. In general, intrinsic lightweight controls don't support this property because they can never receive the input focus. The default value for this property is True, but you can set it to False either at design time or run time.

If a control supports the TabStop property, it also supports the TabIndex property, which affects the Tab order sequence—that is, the sequence in which the controls are visited when the user presses the Tab key repeatedly. (See the section "Setting the Tab Order" in Chapter 1.) The TabIndex property is also supported by Label and Frame controls, but since these two controls don't support the TabStop property, the resulting effect is that when the user clicks on a Label or a Frame control (or presses the hot key specified in the Label or Frame Caption property), the input focus goes to the control that follows in the Tab order sequence. You can exploit this feature to use Label and Frame controls to provide hot keys to other controls:

' Let the user press the Alt+N hot key
' to move the input focus on the Text1 control.
Label1.Caption = "&Name"
Text1.TabIndex = Label1.TabIndex + 1

The MousePointer and MouseIcon Properties

These properties affect the shape of the mouse cursor when it hovers over a control. Windows permits a very flexible mouse cursor management in that each form and each control can display a different cursor, and you can also set an application-wide mouse cursor using the Screen global object. Nevertheless, the rules that affect the actual cursor used aren't straightforward:

If you want to show an hourglass cursor, wherever the user moves the mouse, use this code:

' A lengthy routine
Screen.MousePointer = vbHourglass
...
' Do your stuff here
...
' but remember to restore default pointer.
Screen.MousePointer = vbDefault

Here's another example:

' Show a crosshair cursor when the mouse is over the Picture1
' control and an hourglass elsewhere on the parent form.
Picture1.MousePointer = vbCrosshair
MousePointer = vbHourglass

The MouseIcon property is used to display a custom, user-defined mouse cursor. In this case, you must set the MousePointer to the special value 99-vbCustom and then assign an icon to the MouseIcon property:

' Display a red Stop sign mouse cursor. The actual path may differ,
' depending on the main directory where you installed Visual Basic. 
MousePointer = vbCustom
MouseIcon = LoadPicture("d:\vb6\graphics\icons\computer\msgbox01.ico")

You don't need to load a custom mouse cursor at run time using the LoadPicture command. For example, you can assign it to the MouseIcon property at design time in the Properties window, as you can see in Figure 2-3, and activate it only when needed by setting the MousePointer property to 99-vbCustom. If you need to alternate among multiple cursors for the same control but don't want to distribute additional files, you can load additional ICO files in hidden Image controls and switch among them at run time.

Click to view at full size.

Figure 2-3. Visual Basic 6 comes with a lot of ready-to-go custom cursors, icons, and bitmaps in the \GRAPHICS subdirectory.

The Tag Property

All controls support the Tag property, without exception. This is true even for ActiveX controls, including any third-party controls. How can I be so certain that all controls support this property? The reason is that the property is provided by Visual Basic itself, not by the control. Tag isn't the only property provided by Visual Basic to any control: Index, Visible, TabStop, TabIndex, ToolTipText, HelpContextID, and WhatsThisHelpID properties all belong to the same category. These properties are collectively known as extender properties. Note that a few extender properties are available only under certain conditions. For example, TabStop is present only if the control can actually receive the focus. The Tag property is distinctive because it's guaranteed to be always available, and you can reference it in code without any risk of raising a run-time error.

The Tag property has no particular meaning to Visual Basic: It's simply a container for any data related to the control that you want to store. For example, you might use it to store the initial value displayed in a control so that you can easily restore it if the user wants to undo his or her changes.

Other Properties

The Value property is common to several intrinsic controls, namely CheckBox, OptionButton, CommandButton, and scroll bar controls, as well as to many external ActiveX controls. The meaning of this property varies from control to control, but in all cases it's a numerical or Boolean property.

The Index property is the key to building control arrays, a nifty Visual Basic feature that helps you create more versatile programs. (I explain control arrays more fully in Chapter 3.) If you don't want to create a control array, just leave this property blank in the Properties window at design time. Note that this property is read-only at run time for controls that belong to a control array. Note that Visual Basic raises an error if you reference the Index property of a control that doesn't belong to a control array.

Most intrinsic controls support the Appearance property, which can be assigned at design time only and is read-only at run time. By default, Visual Basic creates controls with a three-dimensional aspect, unless you modify the value of this property to 0-Flat. You might decide to do so for visual consistency with older programs. For all your new applications, you should simply forget about the Appearance property and leave it at its default value (1-3D).

You can have Visual Basic automatically attach a control to the border of its parent window by setting its Align property to a non-Null value. Only two intrinsic controls support this property—PictureBox and Data controls—but several external ActiveX controls can be aligned in this way. Possible values for this property are 0-None, 1-Align Top, 2-Align Bottom, 3-Align Left, and 4-Align Right.

The BorderStyle property is supported by a few intrinsic controls, namely the TextBox, Label, Frame, PictureBox, Image, and OLE controls. You can set this property to 0-None to suppress a border around the controller to 1-Fixed Single to draw it. Forms also support this property, but they allow different settings (as you'll see later in this chapter).

ToolTips are those tiny, usually yellow windows that appear in most Windows applications when you move the mouse over a control or an icon and keep the mouse pointer still for a second or two. (Figure 2-4 shows you helpful advice from a ToolTip.) Until Visual Basic 4, developers had to create special routines or buy third-party tools to add this functionality to their programs. In Visual Basic 5 and 6, you only have to assign a string to the ToolTipText property of the control. Unfortunately, form objects don't support this property. Note that you have no control over the position or size of ToolTip windows and can modify their foreground and background color only on a systemwide basis. (Open the Control Panel window, double-click on the Display icon, and then move to the Appearance tab of the Display Properties dialog box where you can change the font and the background color of your ToolTips.)

Figure 2-4. A tiny ToolTip tells you to enter your name.

The DragMode and DragIcon properties (as well as the Drag method) were used to drag controls on the form, but they have been superseded by the OLExxxx methods and properties. The old properties are still included for backward compatibility, but you shouldn't use them if you want to make your application conform to Windows 95 standards. OLE Drag and Drop properties, methods, and events are described in the "Using Drag-and-Drop" section of Chapter 9.

You use LinkMode, LinkTopic, LinkItem, and LinkTimeout properties (as well as LinkPoke, LinkExecute, LinkRequest, and LinkSend methods) to enable a control or form to communicate through DDE (Dynamic Data Exchange) protocol with other controls or forms, possibly in another application. Before the advent of OLE and COM, Dynamic Data Exchange was the preferred way for two Windows programs to communicate. These days, you shouldn't use this technique because these properties have been maintained only for backward compatibility with applications written in previous versions of Visual Basic. I won't cover DDE in this book.